home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.06 Jun 90 / Fortran Glue / Working App / Test.for < prev    next >
Encoding:
Text File  |  1990-02-14  |  9.1 KB  |  245 lines  |  [TEXT/EDIT]

  1. *    This function illustrates the use of the XFCN, Letsgo, in
  2. *    calling a MacFortran function from HyperCard.  Letsgo does not
  3. *    currently support callbacks from XFCNs.  If there's demand, I
  4. *    will add that feature.
  5.  
  6. *    Letsgo can only load your function and the MacFortran runtime
  7. *    library (f77.rl or m81.rl) dynamically.  It does not support
  8. *    linking with the MacFortran linker.  Thus you will not be able
  9. *    to distribute your function to others who do not own MacFortran
  10. *    and expect them to be able to run it.
  11.  
  12. *    MacFortran will initialize the cursor to the pointer cursor when
  13. *    it starts up.  If you find this distasteful, you can change the cursor
  14. *    with toolbox calls from your function or one of its subroutines.
  15.  
  16. *    The usual paths are searched to locate your function and
  17. *    runtime library.  These are: the System Folder; the folder
  18. *    containing HyperCard (_not_ the folder containing the calling
  19. *    HyperCard stack); and folders in the root directory called
  20. *    "F77 Overlays" (for the runtime) and "Subroutines" (for your
  21. *    function).  Letsgo will not launch your function if it cannot
  22. *    find the runtime library.  If it cannot find your function,
  23. *    it will put up the Standard GetFile dialog and ask you to find it.
  24.  
  25. *    Text files will be written to the folder containing HyperCard,
  26. *    _not_ the folder containing the calling HyperCard stack, unless
  27. *    you supply a path name.  
  28.  
  29. *    Please note that all data in HyperCard is contained in strings.
  30. *    You can use formatted data reads & writes to an internal file
  31. *    (MacFortran Reference Manual, 8.2.4) to convert values in 
  32. *    those strings to integers or reals, etc.
  33.  
  34. *    Neither strings longer than 1k (1024) bytes nor combinations
  35. *    of strings longer than 1k should be written or read using
  36. *    formatted i/o.  Likewise, strings longer than 1k bytes should
  37. *    not be passed to MacFortran's internal functions which 
  38. *    manipulate strings, such as len.  MacFortran will crash if this
  39. *    is done. There is a routine called by this function which 
  40. *    illustrates determination of the length of a string of any
  41. *    size.  Likewise, there is a routine which will read in strings
  42. *    of arbitrary size from internal files.
  43.  
  44. *    Each argument passed to the function can be up to 32k bytes
  45. *    in length.  The length of the argument depends on the length of 
  46. *    the corresponding container in HyperCard.  Containers in the
  47. *    current version of HyperCard (1.2.2) cannot be larger than
  48. *    32 k.
  49.  
  50. *    It is not necessary to assign values to the function result.
  51. *    The result container has been filled with spaces before being passed to
  52. *    you.   Containers passed to Letsgo are not modified in HyperCard,
  53. *    regardless of what you do to them.
  54.  
  55. *    The last character in a HyperCard container is zero, a byte 
  56. *    with no bits set, the null character.  The lengths of the arguments
  57. *    passed to your function do not include this last byte.  You can 
  58. *    shorten the result passed back to HyperCard by stuffing zero in a 
  59. *    byte earlier than the last byte.  This does not appear to be
  60. *    necessary unless you have written additional data into the result
  61. *    container  If you write data past the end of an argument, you will
  62. *    damage HyperCard's heap, possibly with disastrous results 
  63. *    (i.e. total corruption of the stack you're working in).
  64.  
  65. *    Thus far I have not crashed a stack by bombing while in an
  66. *    XFCN, which has occurred maybe once or twice (he-he).
  67. *    HyperCard seems to insulate itself fairly well from XFCNs.  The most
  68. *    common causes of bombs are argument mismatches in type and number.
  69.  
  70. *    HyperCard (at least in my 1 meg machine) only leaves about 32k
  71. *    of room on the stack.  That is the very maximum of room you will
  72. *    have for local variables.  It would be safer to use < 25k. You can
  73. *    crash quite easily if you have a heap-stack collision. Letsgo itself
  74. *    uses about 200 bytes of stack space. If you need more space, put your
  75. *    variables in a common block or use the "save" statement.  Then they 
  76. *    will be allocated on the heap instead of the stack.  Named common 
  77. *    blocks will be disposed of when the subroutine or function which
  78. *    allocated the block ends; thus, in tight memory situations, you can
  79. *    dispose of large arrays used in subroutines by putting them in named 
  80. *    common blocks instead of blank common.  You can increase the heap
  81. *    space by changing the "application memory size" of HyperCard in
  82. *    its info box in the Finder.
  83.  
  84. *    The console window may be called up by setting a flag in Letsgo (make
  85. *    the first argument positive).  You have to CLOSEWINDOW (_not_ 
  86. *    DISPOSEWINDOW) the FRONTWINDOW before returning to Hypercard if you
  87. *    call up the console window.  If you don't, HyperCard will be very
  88. *    unstable.  The console window is suppressed if the first argument
  89. *    is negative.
  90.  
  91. *    If your routine generates an exception which MacFortran can handle,
  92. *    such as divide by zero, MacFortran will write the error message to
  93. *    the front window.  When your program hangs, you have to hit the return
  94. *    key to resume execution, if that's possible.  If your routine generates an
  95. *    exception when the console window is not open and you don't see the error
  96. *    message, try calling up your routine several more times to try to spot the
  97. *    error message before activating the console window.
  98.  
  99. *    The debugger is not available.  You can call your function from a 
  100. *    Fortran main program to use the debugger.
  101.  
  102. *    HyperTalk supports three types of array elements:
  103. *      words, delimited by spaces (ascii 32);
  104. *      items, delimited by commas (ascii 44);
  105. *      lines, delimited by carriage returns (ascii 13).
  106. *    These can be combined to support three-dimensional arrays.
  107. *    You could add other array elements for numeric arrays using
  108. *    other non-numeric ascii character delimiters, thereby increasing
  109. *    the possible number of dimensions.
  110.  
  111. *    MacFortran's formatted i/o to internal files with list-directed
  112. *    editing (Fmt=*    ) separates output records by carriage returns in
  113. *    implied do loops.  Input records under the same conditions need
  114. *    to be separated by spaces.  Thus the easiest HyperCard form for 
  115. *    one-dimensional input arrays is a set of words.  Output arrays are
  116. *    most easily output as a set of lines.  Remember to not use formatted
  117. *    i/o for strings longer than 1024 bytes.  I do not currently know
  118. *    how otherwise to access separate records in internal files using
  119. *    read and write statements; it undoubtedly can be done by someone
  120. *    more knowledgable about Fortran than I.  A method based on pointer
  121. *    manipulation is illustrated in the following function.  The method 
  122. *    also illustrates how to convert items to words, etc.  I also have 
  123. *    written an assembly routine which does this located in FiveXFCN.bin
  124. *    in dl 11 of the HyperCard forum of MAUG on CompuServe.
  125.  
  126. *    This function illustrates reading data from a one-dimensional
  127. *    array of words into a real*8 variable. The data is massaged
  128. *    a bit and spat back to HyperCard in the function result.  The
  129. *    function also illustrates two methods to determine the length
  130. *    of an argument, and an alternative method for inputting data. 
  131. *    Finally, the function writes some data to a text file.
  132.     
  133.         character*(*) function test(a1)
  134.     
  135.     character     a1*(*)
  136.  
  137.     integer*4     i,j
  138.     integer*4     lena1
  139.     real*8        temp(4)    
  140.     
  141.     open(10,file='testout',status='new')
  142.     write(10,*) a1            !don't try to write uninitialized 
  143.                     !character vars!
  144.                     !don't try to write vars longer
  145.                     !than 1k!
  146.                     
  147. * two methods for getting the length of a variable
  148.     lena1 = longle(a1)        !method 1
  149.     write(10,*) lena1
  150.                     !method 2
  151.     lena1 = len(a1)            !don't use this method with
  152.     write(10,*) lena1        !arguments longer than 1k!
  153.     
  154. * read in some data, massage, and return
  155.     read(a1,*) (temp(i),i=1,3,1)    !read from an internal file
  156.     temp(4) = 0
  157.     do (i=1,3,1)
  158.       temp(4) = temp(4) + temp(i)
  159.     repeat
  160.     write(test,*) (temp(i),i=1,4,1) !write to an internal file
  161.     write(10,*) a1, (temp(i),i=1,4,1)    !write to disk
  162.     
  163. * alternative method to read in data
  164.     call input(a1,temp)
  165.     write(10,*) (temp(i),i=1,3,1)
  166.     
  167.     return
  168.     
  169.     end
  170.  
  171.  
  172. *Function to return the length of a HyperCard container
  173.  
  174. *n.b. This method works only with HyperCard containers
  175.  
  176.     integer*4 function longle(a1)
  177.     
  178.     implicit none
  179.     
  180.     integer*4 ptra1,i
  181.         integer PTR,toolbx
  182.         parameter (PTR=z'c0000000')
  183.     
  184.     ptra1 = toolbx(PTR,a1)
  185.  
  186.     i = 0
  187.     do
  188.       if (byte(ptra1 + i) = 0) exit        !don't count the tailing zero
  189.       i=i+1
  190.     repeat
  191.     longle = i
  192.     
  193.     return
  194.     end
  195.     
  196. * convert a1 to items and read three real*8 nums from it
  197.  
  198. * conceptually, this pointer arithmatic is the same as treating
  199. * each character in the string as a separate element of an array
  200.       
  201.     subroutine input(a1,temp)
  202.     
  203.     implicit none
  204.     
  205.     real*8 temp(4)
  206.     integer*4 ptra1,i,j,PTR,toolbx
  207.     integer*1 bytie    
  208.     character a1*(*),itemelement(50)*1, item*50
  209.     
  210.     equivalence (itemelement,item)
  211.     
  212.         parameter (PTR=z'c0000000')
  213.     
  214.     ptra1 = toolbx(PTR,a1)
  215.  
  216. *convert a1 from words to items for the hell of it
  217.     i = 0
  218.     do (60 times)
  219.       if (byte(ptra1 + i) = 32) byte(ptra1 +i) = 44
  220.       i=i+1
  221.     repeat
  222.     
  223. *read three real*8 items from a1
  224.     i=1
  225.     j=1
  226.     do
  227.       item = ' '
  228.       do
  229.         bytie = byte(ptra1+i-1)
  230.         if (bytie = 44 .or. bytie = 0) exit    !end of item or container
  231.         itemelement(i) = bytie
  232.         i = i+1
  233.       repeat
  234.       read(item,*) temp(j)
  235.       i=i+1
  236.       j=j+1
  237.       if (i=2) j=j-1            !delete empty items
  238.       if (bytie = 0 .or. j=3) exit         !end of container or 3 items read
  239.     repeat
  240.     
  241.     return
  242.     end
  243.       
  244.  
  245.